package com.xiaozhengkeji.colastartboot.handler;

import com.xiaozhengkeji.colastartboot.annotation.IPFlowValve;
import com.xiaozhengkeji.colastartboot.bean.ResponseBean;
import com.xiaozhengkeji.colastartboot.bean.type.ResCodeType;
import com.xiaozhengkeji.colastartboot.config.RedisIndexConfig;
import com.xiaozhengkeji.colastartboot.utils.AddressesUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import wiki.xsx.core.util.RedisUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * IP限流处理器
 */
@Aspect
@Component
@Slf4j
public class IPFlowValveHandler {

    @Autowired(required = false)
    private HttpServletRequest request;

    /**
     * Controller层切点,注解方式
     */
    @Pointcut("@annotation(com.xiaozhengkeji.colastartboot.annotation.IPFlowValve)")
    public void controllerAspect() {
    }


    /**
     * AOP限流
     */
    @ResponseBody
    @Around(value = "controllerAspect()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Signature signature = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        //获取目标方法
        Method targetMethod = methodSignature.getMethod();
        if (targetMethod.isAnnotationPresent(IPFlowValve.class)) {
            //获取目标方法的@IPFlowValve注解
            IPFlowValve ipFlowValve = targetMethod.getAnnotation(IPFlowValve.class);
            //拿到redis缓存  先获取key
            String clientIP = AddressesUtil.getIpAddress(request);
            String redisKey = clientIP + "_" + ipFlowValve.urlLogo() + "_IPFlowValve";
            log.info(redisKey);
            Long redisClientIPValve = RedisUtil.getNumberHandler(RedisIndexConfig.IPFlowValveIndex).getLong(redisKey);
            if (redisClientIPValve != null) {
                if (redisClientIPValve > ipFlowValve.limit()) {
                    //已经超流直接返回  //打印日志 + 存入数据库
                    log.info("IP[{}]访问Url地址[{}],超出阈值,请注意是否异常流量!", clientIP, request.getRequestURI());
                    return new ResponseBean(ResCodeType.Error, ipFlowValve.message(), null, null);
                } else {
                    //先+1在存入数据库
                    RedisUtil.getNumberHandler(RedisIndexConfig.IPFlowValveIndex).addLong(redisKey, 1);
                    return proceedingJoinPoint.proceed();
                }
            } else {
                RedisUtil.getNumberHandler(RedisIndexConfig.IPFlowValveIndex).setLong(redisKey, 1L, ipFlowValve.time(), TimeUnit.SECONDS);
                return proceedingJoinPoint.proceed();
            }
        }
        return proceedingJoinPoint.proceed();
    }
}
